package com.us.usws.support.ext;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.ClassPath;
import com.google.common.reflect.ClassPath.ClassInfo;
import com.google.inject.Binder;
import com.google.inject.Module;
import com.google.inject.Scopes;

public class SiteGuiceModule implements Module {

	private static Log log = LogFactory.getFactory().getInstance(SiteGuiceModule.class);
	private static final String[] pkgs = { "com.us.usws.service.ro", "com.us.usws.service.cud" };

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public void configure(Binder binder) {

		//scan service/service impl automatically.
		ClassPath cp;
		try {
			cp = ClassPath.from(Thread.currentThread().getContextClassLoader());
		} catch (IOException e) {
			log.error("Cannot get current classloader.", e);
			return;
		}

		//auto get classes under the pack
		Map<String, Class<?>> clzIMap = new HashMap<String, Class<?>>();
		Map<String, Class<?>> clzImplMap = new HashMap<String, Class<?>>();

		//scan packages.
		for (String eachPkg : pkgs) {
			clzIMap.clear();
			clzImplMap.clear();

			ImmutableSet<ClassInfo> clzs = cp.getTopLevelClassesRecursive(eachPkg);
			for (ClassInfo each : clzs) {
				String name = each.getSimpleName();

				if (name.endsWith("Impl")) {
					String iName = name.substring(0, name.length() - 4);
					try {
						clzImplMap.put(iName, each.load());
					} catch (Exception e) {
						//cannot load
						log.warn("Cannot load class [" + iName + "] -- " + e.getMessage());
						continue;
					}
				} else {
					clzIMap.put(name, each.load());
				}
			}

			//loop in cached map
			for (String key : clzIMap.keySet()) {

				if (clzImplMap.containsKey(key)) {
					Class<?> from = clzIMap.get(key);
					Class to = clzImplMap.get(key);
					if (from.isAssignableFrom(to)) {
						log.trace("{GuiceInjectorBinder} :: binding from [" + from.getName() + "] to [" + to.getName() + "].");
						binder.bind(from).to(to.asSubclass(from)).in(Scopes.SINGLETON);
					}
				}
			}
		}

		//add other manually bindings

	}
}